@{title(CONF.name)}
@{layout('')}

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
	<meta http-equiv="X-UA-Compatible" content="IE=10" />
	<meta name="robots" content="all,follow" />
	@{import('spa.min@19.css', 'spa.min@19.js')}
	<script src="@{REPO.ui}"></script>
	@{import('meta', 'head', 'default.css + editor.min@1.css + editor.css', 'filesaver.min.js + editor.min@1.js + uibuilder.min@1.js + editor.js + func.js', 'favicon.ico')}
</head>
<body@{if PREF.darkmode} class="ui-dark"@{fi}>

	<ui-component name="exec"></ui-component>
	<ui-component name="locale" config="requests:1;language:@{controller.language}"></ui-component>
	<ui-component name="windows" path="common.windows" config="zindex:50"></ui-component>
	<ui-component name="imageviewer" config="unknown:@(Unknown image)"></ui-component>

	<ui-component name="LAZY menu" config="style:2"></ui-component>
	<ui-component name="LAZY approve" config="cancel:@(Cancel)"></ui-component>
	<ui-component name="LAZY autocomplete"></ui-component>
	<ui-component name="LAZY message" config="style:2"></ui-component>
	<ui-component name="LAZY notify" config="position:bottom right"></ui-component>
	<ui-component name="LAZY spotlight"></ui-component>
	<ui-component name="LAZY fileuploader"></ui-component>
	<ui-component name="LAZY clipboard"></ui-component>
	<ui-component name="LAZY icons" config="list:@{#}/icons-db.html"></ui-component>
	<ui-component name="LAZY directory" config="placeholder:@(Search);create:@(Create)"></ui-component>
	<ui-component name="LAZY colorpicker"></ui-component>
	<ui-component name="LAZY prompt" config="cancel:@(Cancel);submit:@(OK)"></ui-component>

	<ui-component name="datepicker" config="today:@(Today);days:@(Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);clear:@(Clear);months:@(January,February,March,April,May,Juny,July,August,September,October,November,December)"></ui-component>
	<ui-component name="edit"></ui-component>
	<ui-component name="paste"></ui-component>
	<ui-component name="shortcuts"></ui-component>
	<ui-component name="loading" config="style:2"></ui-component>
	<ui-component name="markdown" config="highlight:false;charts:false"></ui-component>
	<ui-component name="errorhandler"></ui-component>
	<ui-component name="hashchange"></ui-component>

	<ui-component name="dropfiles" path="null" config="exec:common/dragdrop;check:common/dragdropcheck" class="hidden">
		@(Drag &amp; Drop FlowStream)
	</ui-component>

	<ui-component name="importer" path="common.form" config="if:importform;url:@{#}/forms/import.html"></ui-component>

	<header>

		<ui-bind path="common.env" config="template" title="@(Environment)" class="env">
			<script type="text/html">
				<span class="badge badge-medium badge-{{ if value === 'dev' }}red{{ else if value === 'test' }}orange{{ else }}green{{ fi }}">{{ value }}</span>
			</script>
		</ui-bind>

		<span class="search exec pull-right" data-exec="common/search" title="@(Search) (F1)"><i class="ti ti-search"></i></span>
		<span class="console exec pull-right" data-exec="common/console" title="@(Server log)"><i class="ti ti-bug"></i></span>

		@{if user.openplatform}
		<span class="mainmenu"><a href="@{user.openplatform}"><i class="ti ti-menu"></i></a></span>
		@{else}
		<span class="mainmenu exec" data-exec="common/focus" data-id="main"><i class="ti ti-menu"></i></span>
		@{fi}

		<ui-bind path="common.tabs" config="template:div" class="tabs block">
			<script type="text/html">
				{{ foreach m in value }}
					{{ if !m.noclose }}<div class="exec{{ if m.focused }} selected{{ fi }}" data-exec="common/focus" data-id="{{ m.id }}">{{ if !m.noclose }}<i class="ti ti-times exec" data-exec="common/close"></i>{{ fi }}{{ m.name }}</div>{{ fi }}
				{{ end }}
			</script>
		</ui-bind>
		<div class="pull-right">
			<ui-component name="virtualwire" path="common.page" class="toolbar"></ui-component>
		</div>
	</header>

	<div class="appmenu">
		<ui-component name="noscrollbar" config="parent:window;margin:60" class="invisible">
			<ui-component name="selected" path="common.page" config="selector:.exec;attr:id">
				<ui-bind path="common.menu" config="template" class="block">
					<script type="text/html">
						{{ foreach m in value }}
							{{ if m === '-' }}
							<hr />
							{{ else if m.hidden !== true }}
							<div class="exec" data-exec="common/menu" title="{{ m.name }}" data-id="{{ m.id }}"><i class="{{ m.icon }}"></i></div>
							{{ fi }}
						{{ end }}
					</script>
				</ui-bind>
			</ui-component>
		</ui-component>
	</div>

	<div class="appmain">

		<ui-component name="ready" config="rclass:invisible" class="invisible">

			<div class="landing">
				<ui-component name="parts" path="common.tabs" config="parent:window;margin:60;focus:common/selected"></ui-component>
			</div>

			<ui-component name="importer" path="common.form" config="if:streamform;url:@{#}/forms/stream.html"></ui-component>
			<ui-component name="importer" path="common.form" config="if:variablesform;url:@{#}/forms/variables.html"></ui-component>
			<ui-component name="importer" path="common.form" config="if:welcomeform;url:@{#}/forms/welcome.html"></ui-component>

			@{if user.sa}
			<ui-component name="importer" path="common.form" config="if:templatesform;url:@{#}/forms/templates.html"></ui-component>
			<ui-component name="importer" path="common.form" config="if:settingsform;url:@{#}/forms/settings.html"></ui-component>
			<ui-component name="importer" path="common.form" config="if:passwordform;url:@{#}/forms/password.html"></ui-component>
			<ui-component name="importer" path="common.form" config="if:publishform;url:@{#}/forms/publish.html"></ui-component>
			@{fi}

			@{if user.sa || user.permissions.includes('create')}
			<ui-component name="importer" path="common.form" config="if:newform;url:@{#}/forms/new.html"></ui-component>
			@{fi }

		</ui-component>

	</div>

	@{json(model, 'pluginsdata')}
	@{json(user.json ? user.json() : user, 'userdata')}

	<script>

		DEF.fallback = '@{#}/cdn/j-{0}.html';
		DEF.versionhtml = '@{Flow.version}';

		// Due to plugins
		W.BREADCRUMB = { add: NOOP };

		var common = {};
		var user = PARSE('#userdata');

		common.openplatform = NAV.query.openplatform || '';

		if (common.openplatform) {
			(function() {
				var hostname = common.openplatform.substring(0, common.openplatform.indexOf('/', 10));
				hostname && IMPORT(hostname + '/iframe.js');
				common.openplatform = '?openplatform=' + encodeURIComponent(common.openplatform);
			})();
		}

		common.clientid = GUID(5) + Date.now().toString(36);
		common.breadcrumb = [];
		common.plugins = PARSE('#pluginsdata');
		common.language = '@{controller.language}';
		common.tabs = [{ id: 'main', name: '@(Flows)', icon: 'ti ti-home', noclose: true, import: '@{#}/parts/flows.html' }];
		common.secret = 'flowstream';
		common.layout = '';
		common.windows = [];
		common.page = 'flows';
		common.designer = '@{#}/designer/';
		common.totalversion = +'@{F.version}';
		common.workers = '@{CONF.flowstream_worker}' !== 'false';
		common.env = '@{PREF.env}';
		common.templates = '@{PREF.templates}';
		common.bundle = '@{F.isBundle}' === 'true';
		common.cl = {}; // for additional codelists

		if (user.color)
			APPEARANCE({ color: user.color });

		document.title += ' (' + common.env + ')';

		(function() {
			DEF.api = '@{#}@{CONF.$api}' + common.openplatform;
		})();

		ON('@flag showloading', function() {
			EXEC('-loading/show');
		});

		ON('@flag hideloading', function() {
			EXEC('-loading/hide', 1000);
		});

		// Error handling
		ON('ERROR', function(response) {

			if (!(response instanceof Array))
				response = [response];

			var err = [];
			var login = false;
			for (var m of response) {
				if (m.name === '401')
					login = true;
				err.push(m.error);
			}

			EXEC('-message/warning @hideloading', err.join('<br />'));
			login && location.reload(true);
		});

		function shortcutsprocess(type) {
			return function(e) {
				var t = e.target.target;
				if (t !== 'TEXTAREA' && t !== 'INPUT') {
					var win = $('.ui-parts-focused');
					if (win.length) {
						var w = win.find('iframe')[0];
						w && w.contentWindow.postMessage(STRINGIFY({ TYPE: 'shortcut', key: type }), '*');
					}
				}
			};
		}

		FIND('shortcuts', function(com) {
			com.register('CMD+ENTER, CTRL+ENTER', shortcutsprocess('CMD+ENTER'));
			com.register('CMD+D, CTRL+D', shortcutsprocess('CMD+D'), true);
			com.register('CMD+F, CTRL+F', shortcutsprocess('CMD+F'), true);
			com.register('CMD+TAB, ALT+TAB', function() {
				var index = common.tabs.findIndex('focused', true) + 1;
				EXEC('-parts/focus', common.tabs[index] ? common.tabs[index].id : common.tabs[0].id);
			}, true);
			com.register('remove', shortcutsprocess('remove'));
			com.register('save', shortcutsprocess('save'), true);
			com.register('F1', AEXEC('common/search'), true);
			com.register('F10', AEXEC('common/console'), true);
		});

		EXEC(true, '-loading/hide', 500);

		FUNC.import = function(callback) {
			SET('importform @default', { callback: callback });
			SET('common.form', 'importform');
		};

		FUNC.cleanflow = function(data) {
			delete data.origin;
			delete data.variables2;
			delete data.unixsocket;
			delete data.directory;
			delete data.size;
			delete data.asfiles;
			delete data.env;
			delete data.sandbox;
			return data;
		};

		Thelpers.url = function(val) {
			var index = val.indexOf('/', 10);
			return index === -1 ? val : val.substring(0, index);
		};

		PLUGIN('common', function(exports) {

			var model = exports.model;
			var checksum;
			var loaded = false;

			(function() {
				model.plugins.quicksort('position');
				model.plugins.forEach(function(plugin) {
					plugin.url = model.root + plugin.id + '/';
					plugin.import && $(document.body).append('<ui-import config="url:{0};id:_{1}"></ui-import>'.format('@{#}/_' + plugin.id + '/' + plugin.import, plugin.id));
				});
			})();

			exports.refresh = function() {
				exports.tapi('streams ERROR', function(response) {

					var groups = {};

					for (var item of response) {

						if (!item.group)
							item.group = '#';

						if (groups[item.group])
							groups[item.group].items.push(item);
						else
							groups[item.group] = { id: item.name, name: item.name, items: [item] };
					}

					var arr = [];
					var form = [];

					for (var key in groups) {
						if (key !== '#')
							form.push({ id: key, name: key });
						arr.push({ name: key === '#' ? '' : key, items: groups[key].items });
						groups[key].items.quicksort('name');
					}

					arr.quicksort('name');
					exports.set('groups', arr);
					exports.set('groupsform', form);
					exports.set('items', response);

					if (!loaded) {
						loaded = true;
						if (location.hash) {
							let item = response.findItem('id', location.hash.substring(1));
							if (item)
								setTimeout(() => exports.open(item), 500);
						}
					}


				});
			};

			exports.focus = function(el) {

				var id = ATTRD(el);

				if (id === 'main') {

					if (model.page !== 'flows') {
						exports.set('page', 'flows');
						EXEC('-parts/focus', id);
						return;
					}

					var opt = {};
					opt.element = el;
					opt.align = 'left';
					opt.items = CLONE(model.menu);

					var index = opt.items.findIndex('id', 'settings');
					if (index !== -1)
						opt.items.splice(index + 1, 0, { id: 'cdnclear', name: '@(Clear CDN cache)', icon: 'ti ti-recycle' });

					opt.callback = exports.menu;
					EXEC('-menu/show', opt);
				} else {
					location.hash = id;
					exports.nul('page');
					EXEC('-parts/focus', id);
				}
			};

			exports.selected = function(tab) {
				if (tab) {
					if (tab.id === 'main') {
						location.hash = '';
						if (model.page !== 'flows')
							exports.set('page', 'flows');
					} else
						location.hash = tab.id;
				}
			};

			exports.dragdrop = function(files) {
				var reader = new FileReader();
				reader.onload = function() {
					var data = PARSE(reader.result);
					if (data && data.components && data.design && data.id && data.name) {
						exports.tapi('clipboard_import @showloading ERROR', { data: reader.result }, function(response) {
							exports.refresh();
							setTimeout(function() {
								exports.tapi('streams_read/{0} ERROR'.format(response.value), function(response) {
									SET('streamform @reset @hideloading', response);
									SET('common.form', 'streamform');
								});
							}, 1000);
						});
						return;
					}
					EXEC('-message/warning', '@(Invalid file content)');
				};
				reader.readAsText(files[0]);
			};

			exports.dragdropcheck = function(e) {
				var model = exports.model;
				var selected = model.tabs.findItem('focused', true);
				return !selected || selected.id === 'main';
			};

			exports.close = function(el, e) {

				e.stopPropagation();
				e.preventDefault();

				location.hash = '';
				EXEC('-parts/close', ATTRD(el));

				setTimeout(function() {
					if (model.tabs.length === 1 && model.page !== 'flows')
						exports.set('page', 'flows');
				}, 80);

			};

			exports.open = function(el) {

				var id = ATTRD(el);
				var item = model.tabs.findItem('id', id);

				if (id !== 'main')
					exports.nul('page');

				if (item) {
					if (!item.focused)
						EXEC('-parts/focus', item.id);
					return;
				}

				if (!model.appmenuwidth)
					model.appmenuwidth = $('.appmenu').width();

				var flow = model.items.findItem('id', id);
				var url = location.origin.replace(/^http/, 'ws') + '@{#}/flows/{0}/'.format(id) + common.openplatform;

				location.hash = id;
				item = {};
				item.id = id;
				item.icon = flow.icon;
				item.name = flow.name;
				item.html = ('<iframe src="' + common.designer + '?darkmode={1}&socket={2}&components={3}&language={4}" scrolling="no" frameborder="0" class="iflowstream" style="width:{5}px"></iframe>').format(id, $('body').hclass('ui-dark') ? '1' : '0', encodeURIComponent(url), encodeURIComponent(common.components || '') + common.openplatform ? ('&' + common.openplatform.substring(1)) : '', common.language, WW - model.appmenuwidth);
				item.focus = 'common/focusiframe';
				EXEC('-loading/show');
				EXEC('-loading/hide', 2000);
				exports.push('tabs', item);
			};

			exports.focusiframe = function(el, item) {
				el[0].firstChild.contentWindow.focus();
			};

			exports.contextmenu = function(el, e) {

				var id = el.attrd2('id');
				var opt = {};

				if (el.hclass('exec3')) {
					opt.x = e.pageX;
					opt.y = e.pageY;
				} else {
					opt.element = el;
					opt.align = 'right';
				}

				var model = exports.model;
				var item = model.items.findItem('id', id);
				var paused = false;
				var parent = el.closest('.flowstreams');

				opt.items = [];

				if (user.sa)
					opt.items.push({ id: 'variables', name: '@(Variables)', icon: 'ti ti-variables', classname: 'b' });

				if (common.totalversion > 4045 && item.stats) {
					if (item.stats.paused) {
						opt.items.push({ id: 'play', name: '@(Play)', icon: 'ti ti-play green' });
						paused = true;
					} else
						opt.items.push({ id: 'pause', name: '@(Pause)', icon: 'ti ti-pause red' });
				}

				if (opt.items.length)
					opt.items.push('-');

				if (top === W)
					opt.items.push({ id: 'newtab', name: '@(Open in new tab)', icon: 'ti ti-window-alt' });

				opt.items.push({ id: 'edit', name: '@(Edit)', icon: 'ti ti-pencil' });

				if (user.sa || user.permissions.includes('create'))
					opt.items.push({ id: 'clone', name: '@(Clone)', icon: 'ti ti-clone' });

				// opt.items.push({ id: 'copy', name: '@(Copy to clipboard)', icon: 'ti ti-copy' });
				opt.items.push({ id: 'copy2', name: '@(Copy as JSON)', icon: 'ti ti-copy' });
				opt.items.push({ id: 'download', name: '@(Download)', icon: 'ti ti-download' });

				if (common.workers)
					opt.items.push({ id: 'restart', name: '@(Restart)', icon: 'ti ti-sync' });

				if (user.sa || user.permissions.includes('remove')) {
					opt.items.push({ id: 'publish', name: '@(Publish to the community)', icon: 'ti ti-upload' });
					opt.items.push('-');
					opt.items.push({ id: 'remove', name: '@(Remove)', icon: 'ti ti-remove red' });
				}

				opt.callback = function(opt) {
					switch (opt.id) {
						case 'newtab':
							var url = location.origin.replace(/^http/, 'ws') + '@{#}/flows/{0}/'.format(id);
							W.open(location.origin + common.designer + '?darkmode={0}&socket={1}&components={2}'.format($('body').hclass('ui-dark') ? '1' : '0', encodeURIComponent(url + (common.openplatform ? ((url.indexOf('?') === -1 ? '?' : '&') + common.openplatform.substring(1)) : '')), encodeURIComponent(common.components || '')) + (common.openplatform ? ('&' + common.openplatform.substring(1)) : ''));
							break;
						case 'pause':
						case 'play':
							exports.tapi(QUERIFY('streams_pause/{0} ERROR'.format(id), { is: paused ? 0 : 1 }), function() {
								parent.find('figure[data-id="{0}"]'.format(id)).tclass('paused', !paused);
								if (item.stats)
									item.stats.paused = !paused;
							});
							break;
						case 'restart':
							EXEC('-approve/show', '@(Are you sure you want to restart selected FlowStream "{0}"?)'.format(item.name), '"ti ti-sync" @(Restart)', function() {
								exports.tapi('streams_restart/{0} ERROR'.format(id), AEXEC('-notify/success', '@(FlowStream "{0}" is restarting ...)'.format(item.name)));
							});
							break;
						case 'variables':
							TAPI('variables?id=' + id, AEXEC('-message/response', function(response) {
								var model = {};
								model.variables = response;
								model.callback = function(model) {
									exports.tapi('variables_save ERROR', { id: id, data: model }, AEXEC('-notify/success', '@(Variables have been changed successfully.)'));
								};
								SET('variablesform @reset', model);
								SET('common.form', 'variablesform');
							}));
							break;
						case 'copy':
						case 'copy2':
						case 'clone':
						case 'download':
							exports.tapi('clipboard_export/{0} ERROR'.format(id), function(response) {

								if (opt.id === 'download') {
									var blob = new Blob([JSON.stringify(FUNC.cleanflow(JSON.parse(response.value)), null, '\t')], { type: 'text/plain; charset=utf-8' });
									saveAs(blob, item.name + '.json');
									return;
								}

								if (opt.id === 'copy' || opt.id === 'copy2') {
									EXEC('-clipboard/copy', opt.id === 'copy' ? ENCRYPT(response.value, common.secret, 'flow') : JSON.stringify(FUNC.cleanflow(JSON.parse(response.value)), null, '\t'));
									EXEC('-notify/success', '@(The FlowStream has been copied into the clipboard)');
								} else {
									exports.tapi('clipboard_import @showloading ERROR', { data: response.value }, function(response) {
										exports.refresh();
										setTimeout(function() {
											exports.tapi('streams_read/{0} ERROR'.format(response.value), function(response) {
												SET('streamform @reset @hideloading', response);
												SET('common.form', 'streamform');
											});
										}, 1000);
									});
								}
							});
							break;
						case 'edit':
							exports.tapi('streams_read/{0} @showloading ERROR'.format(id), function(response) {
								SET('streamform @reset', response);
								SET('common.form @hideloading', 'streamform');
							});
							break;
						case 'remove':
							user.sa && EXEC('-approve/show', '@(Are you sure you want to remove selected FlowStream "{0}"?)'.format(item.name), '"ti ti-remove" @(Remove)', function() {
								exports.tapi('streams_remove/{0} ERROR'.format(id), exports.refresh);
							});
							break;
						case 'publish':
							exports.tapi('clipboard_export/{0} ERROR'.format(id), function(response) {
								var data = {};
								data.type = 'flowstream';
								data.name = item.name;
								data.email = CACHE('email') || '@';
								data.data = JSON.stringify(FUNC.cleanflow(PARSE(response.value)), null, '\t');
								SET('publishform @reset', data);
								SET('common.form', 'publishform');
							});
							break;
					}
				};
				EXEC('-menu/show', opt);
			};

			exports.settings = function() {
				exports.tapi('settings @showloading ERROR', function(response) {

					var data = {};

					for (var m of response.items) {
						if (m.type !== 'group')
							data[m.id] = m.value;
					}

					response.data = data;
					SET('settingsform @reset @hideloading', response);
					SET('common.form', 'settingsform');
				});
			};

			exports.mainmenu = function() {
				var items = [];

				items.push({ id: 'flows', name: '@(Flow)', icon: 'ti ti-home' });

				if (user.sa || user.permissions.includes('create')) {
					items.push({ id: 'create', name: '@(Create new)', icon: 'ti ti-plus-circle green' });
					items.push({ id: 'import', name: '@(Import FlowStream)', icon: 'ti ti-download', hidden: true });
				}

				items.push({ id: 'search', name: '@(Search)', icon: 'ti ti-search' });

				if (user.sa) {
					items.push({ id: 'templates', name: '@(Templates)', icon: 'ti ti-cloud-download', hidden: true });
					items.push({ id: 'variables', name: '@(Variables)', icon: 'ti ti-variables', classname: 'b', hidden: true });
				}

				if (items.length)
					items.push('-');

				if (!model.openplatform && !user.openplatform)
					items.push({ id: 'password', name: '@(Change credentials)', icon: 'ti ti-key' });

				if (user.sa) {
					items.push({ id: 'settings', name: '@(Settings)', icon: 'ti ti-cog' });
					if (model.bundle)
						items.push({ id: 'update', name: '@(Update bundle)', icon: 'ti ti-sync', hidden: true });
				}

				if (model.plugins.length) {
					var tmp = [];
					for (var plugin of model.plugins) {
						if (!plugin.hidden)
							tmp.push({ id: 'plugin' + plugin.id, name: plugin.name, icon: plugin.icon });
					}
					if (tmp.length) {
						items.push('-');
						items.push.apply(items, tmp);
					}
				}

				if (!model.openplatform) {
					items.push('-');
					items.push({ id: 'logout', name: '@(Sign out)', icon: 'ti ti-sign-out red' });
				}

				if (items.last() === '-')
					items.pop();

				exports.set('menu', items);
			};

			exports.menu = function(el) {
				var id = ATTRD(el);
				switch (id) {

					case 'flows':
						location.hash = '';
						exports.set('page', 'flows');
						EXEC('-parts/focus', 'main');
						break;

					case 'update':
						EXEC('-approve/show', '<i class="ti ti-warning red"></i><b>@(WARNING):</b> @(Are you sure you want to update bundle of the Total.js Flow? It is a hazardous step.)', '"ti ti-sync" @(Upload bundle)', function() {
							var opt = {};
							opt.multiple = false;
							opt.url = '/fapi/update/' + model.openplatform;
							opt.callback = function(response, err) {
								if (err) {
									EXEC('-message/warning', err);
								} else {
									EXEC('-loading/show');
									setTimeout(() => location.reload(), 5000);
								}
							};
							EXEC('-fileuploader/upload', opt);
						});
						break;

					case 'logout':
						AJAX('GET @{#}/fapi/logout/ @showloading', () => location.href = '/?login=1');
						break;

					case 'import':
						FUNC.import(function(data, hide) {
							data = data.trim();
							var obj = PARSE(data);
							if (obj && obj.components && obj.id && obj.name && obj.design) {
								data = STRINGIFY(obj);
								exports.tapi('clipboard_import @showloading ERROR', { data: data }, function(response) {
									exports.refresh();
									setTimeout(function() {
										exports.tapi('streams_read/{0} ERROR'.format(response.value), function(response) {
											SET('streamform @reset @hideloading', response);
											SET('common.form', 'streamform');
										});
									}, 1000);
								});
								hide();
							} else
								EXEC('-message/warning', '@(Invalid data)');
						});
						break;
					case 'opensource':
						exports.set('form', 'templatesform');
						break;
					case 'create':
					case 'settings':
					case 'password':
					case 'variables':
						exports[id]();
						break;
					case 'cdnclear':
						EXEC('-approve/show', '@(Are you sure you want to clear the CDN cache for UI components?)', ':ti ti-recycle: @(Clear)', () => exports.tapi('cdn_clear ERROR', AEXEC('-message/success', '@(The CDN cache has been cleared successfully)')));
						break;
					case 'templates':
						SET('common.form', 'templatesform');
						break;
					case 'search':
						exports.search();
						break;
					default:

						if (id.substring(0, 6) === 'plugin') {
							EXEC('-parts/focus', 'main');
							exports.set('page', id);
						}

						break;
				}
			};

			exports.create = function() {
				SET('streamform @default', {});
				SET('common.form', 'streamform');
			};

			exports.password = function() {
				exports.tapi('auth ERROR', function(response) {
					SET('passwordform @reset', response);
					SET('common.form', 'passwordform');
				});
			};

			exports.variables = function() {
				exports.tapi('variables ERROR', function(response) {
					var model = {};
					model.variables = response;
					model.callback = function(model) {
						exports.tapi('variables_save ERROR', { data: model }, AEXEC('-notify/success', '@(Variables have been changed successfully.)'));
					};
					SET('variablesform @reset', model);
					SET('common.form', 'variablesform');
				});
			};

			exports.console = function() {
				var winid = 'console';
				if (model.windows.findItem('id', winid)) {
					EXEC('-windows/hide', winid);
				} else {
					exports.push('windows', { id: winid, cachekey: winid + (screen.width + 'x' + screen.height), html: '<ui-import config="url:/forms/console.html"></ui-import>', title: '@(Real-time server console)', actions: { move: true, autosave: true, menu: true, close: true, maximize: false, minimize: false }, offset: { x: ((WW / 2) - 275) >> 0, y: ((WH / 2) - 250) >> 0, width: 550, height: 200, minwidth: 200, minheight: 100, maxwidth: 800, maxheight: 1200 }, menu: function(el) {
						el.closest('.ui-windows-item').find('pre').empty();
						TAPI('console_clear', NOOP);
					}, make: function(el) {
						el.parent().find('.ui-windows-lastbutton').rclass2('ti').aclass('ti ti-remove');
						el.closest('.ui-windows-item').css('z-index', 50);
						el.aclass('noscrollbar');
					}});
				}
			};

			exports.refresh();

			exports.stats = function() {
				exports.tapi('streams_stats', 'stats');
			};

			ON('resize + resize2', function() {
				$('.iflowstream').css({ width: WW - model.appmenuwidth });
			});

			ON('ready', exports.stats);

			setInterval(function() {
				exports.stats();
				exports.refresh();
			}, 10000);

			$(W).on('message', function(e) {

				var data = e.originalEvent.data;
				if (data)
					data = PARSE(data);

				if (data && data.SOURCE === 'flow') {
					switch (data.TYPE) {
						case 'open':
							var model = exports.model;
							if (data.id.charAt(0) === '@')
								data.id = model.items.findValue('reference', data.id.substring(1), 'id');
							data.id && exports.open(data.id);
							EXEC('-!menu/hide');
							EXEC('-!datepicker/hide');
							break;
						case 'focus':
							var model = exports.model;
							var win = model.windows.findItem('url', data.socket);
							if (win) {
								EXEC('-!menu/hide');
								EXEC('-!datepicker/hide');
								EXEC('-infowindows/focus', win.id);
							}
							break;
						case 'F1':
							EXEC('common/search');
							break;
						case 'F10':
							EXEC('common/console');
							break;
						case 'edit':
							exports.tapi('streams_read/{id} @showloading ERROR'.arg(data), function(response) {
								SET('streamform @reset', response);
								SET('common.form @hideloading', 'streamform');
							});
							break;
					}
				}
			});

			ON('paste', function(text) {
				var data;
				if (!common.form && text.substring(0, 4) === 'flow') {
					data = DECRYPT(text, common.secret, 'flow');
					if (data) {
						EXEC('-approve/show', '@(Are you sure you want to import a Flow from the clipboard?)', '@(Import)', function() {
							TAPI('clipboard_import @showloading ERROR', { data: STRINGIFY(data) }, function(response) {

								if (response.error)
									EXEC('-message/warning', response.error);

								exports.exec('refresh');
								setTimeout(function() {
									TAPI('streams_read/{0} ERROR' + response.value, function(response) {
										SET('streamform @reset', response);
										SET('common.form', 'streamform');
									});
								}, 1000);
							});
						});
					}
				}
			});

			if (NAV.query.welcome) {
				exports.set('form', 'welcomeform');
				setTimeout(() => REDIRECT(NAV.url), 1000);
			}

			exports.mainmenu();

		});


	</script>

</body>
</html>